﻿using Devil;
using GameToolkit;
using GameToolkit.Editor;
using System;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;

using StoryGraphView = GameToolkit.Editor.StoryGraph;

public class StoryGraphEditor : EditorWindow
{
    [SerializeField]
    private VisualTreeAsset m_VisualTreeAsset = default;

    readonly static Type[] sDockTypes = { typeof(StoryGraphEditor), typeof(SceneView) };

    [InitializeOnLoadMethodParallel(ExecutionOrder = InitializeOrder.First)]
    static void InitMethod()
    {
        TaskGraphAsset.OpenGraph = (graph) => OpenGraph(graph, false);
        TaskGraphAsset.OpenAsset = (graph) => OpenAsset(graph, false);
    }

    [MenuItem("Window/Game Toolkit/Task Designer")]
    public static void OpenEditor()
    {
        StoryGraphEditor win = GetWindow<StoryGraphEditor>(sDockTypes);
        win.minSize = new Vector2(640, 480);
        //wnd.titleContent = new GUIContent("StoryGraphEditor");
    }

    public static StoryGraphEditor OpenAsset(TaskGraphAsset asset, bool newWindow)
    {
        if (asset == null)
            return null;
        var array = Resources.FindObjectsOfTypeAll<StoryGraphEditor>();
        var len = array == null ? 0 : array.Length;
        StoryGraphEditor focusWin = null;
        for (int i = 0; i < len; i++)
        {
            var editor = array[i];
            if (editor.hasFocus)
                focusWin = editor;
            if (editor.storyGraphAsset == asset)
            {
                editor.mTaskGraph = null;
                editor.Reopen(asset);
                editor.Focus();
                return editor;
            }
        }
        StoryGraphEditor win;
        if (newWindow)
            win = CreateWindow<StoryGraphEditor>(sDockTypes);
        else
            win = focusWin == null ? GetWindow<StoryGraphEditor>(sDockTypes) : focusWin;
        win.minSize = new Vector2(640, 480);
        if (win.storyGraphAsset != null && win.storyGraphAsset != asset)
        {
            if (!win.ExecuteClearGraph(true))
                return null;
        }
        win.mTaskGraph = null;
        win.Reopen(asset);
        win.Focus();
        return win;
    }

    public static StoryGraphEditor OpenGraph(TaskGraph graph, bool newWindow)
    {
        if (graph == null || graph.asset == null)
            return null;
        var array = Resources.FindObjectsOfTypeAll<StoryGraphEditor>();
        var len = array == null ? 0 : array.Length;
        StoryGraphEditor focusWin = null;
        for (int i = 0; i < len; i++)
        {
            var editor = array[i];
            if (editor.hasFocus)
                focusWin = editor;
            if (editor.storyGraphAsset == graph.asset)
            {
                editor.mTaskGraph = graph;
                editor.Reopen(graph.asset);
                editor.Focus();
                return editor;
            }
        }
        StoryGraphEditor win;
        if (newWindow)
            win = CreateWindow<StoryGraphEditor>(sDockTypes);
        else
            win = focusWin == null ? GetWindow<StoryGraphEditor>(sDockTypes) : focusWin;
        win.minSize = new Vector2(640, 480);
        if (win.storyGraphAsset != null && win.storyGraphAsset != graph.asset)
        {
            if (!win.ExecuteClearGraph(true))
                return null;
        }
        win.mTaskGraph = graph;
        win.Reopen(graph.asset);
        win.Focus();
        return win;
    }

    VisualElement mUxmlRoot;
    ToolbarMenu mFileBtn;
    Button mPingAsset;
    StoryGraphView mGraph;
    Button mSavBtn;
    Button mResetBtn;
    TaskGraph mTaskGraph;
    //ToolbarBreadcrumbs mTreePath;

    TaskGraphAsset mGraphAsset;
    public TaskGraphAsset storyGraphAsset
    {
        get { return mGraphAsset; }
        set
        {
            var clean = mGraphAsset == null && ((object)mGraphAsset) != null;
            //var nil = m_BehaviourTreeAsset == null;
            //var nil2 = value == null;
            if (mGraphAsset != value || clean)
            {
                mGraphAsset = value;
                titleContent.text = value == null ? "<Task Designer>" : value.Title;
                if (mGraph != null)
                    mGraph.asset = value;
                if (mPingAsset != null)
                    mPingAsset.SetEnabled(value != null);
            }
        }
    }

    public void Reopen(TaskGraph graph)
    {
        mTaskGraph = graph;
        if (graph != null)
            Reopen(graph.asset);
    }

    public void Reopen(TaskGraphAsset asset)
    {
        var clean = mGraphAsset == null && ((object)mGraphAsset) != null;
        //var nil = m_BehaviourTreeAsset == null;
        //var nil2 = value == null;
        if (mGraphAsset != asset || clean)
        {
            mGraphAsset = asset;
            titleContent.text = asset == null ? "<Task Designer>" : (mGraph == null ? asset.Title : mGraph.name);
            if (mGraph != null)
            {
                mGraph.asset = asset;
                mGraph.BindRuntimeGraph(mTaskGraph);
            }
            if (mPingAsset != null)
                mPingAsset.SetEnabled(asset != null);
        }
        else if (asset != null)
        {
            OnClickReset();
        }
    }


    private void OnEnable()
    {
        //if (m_NodeProvidor == null)
        //    m_NodeProvidor = ScriptableObject.CreateInstance<BehaviourTreeSearchProvidor>();
        //if (m_DecoratorProvidor == null)
        //    m_DecoratorProvidor = ScriptableObject.CreateInstance<BehaviourTreeSearchProvidor>();

        titleContent.image = StoryNodeLib.GetAssetIcon();
        if (storyGraphAsset == null)
            titleContent.text = "Task Designer";
        else if (mGraph != null && mGraph.IsDirty)
            titleContent.text = $"{storyGraphAsset.name} *";
        else
            titleContent.text = storyGraphAsset.name;
        if (mGraph != null)
            mGraph.BindRuntimeGraph(mTaskGraph);
    }

    private void OnDisable()
    {
        if (mGraph != null)
            mGraph.BindRuntimeGraph(null);
        ExecuteClearGraph(false);
        UnregistCallbacks();
    }

    private void OnDestroy()
    {
        if (mGraph != null)
        {
            mGraph.Dispose();
        }
    }

    public void CreateGUI()
    {
        UnregistCallbacks();

        // Each editor window contains a root VisualElement object
        VisualElement root = rootVisualElement;

        //// VisualElements objects can contain other VisualElement following a tree hierarchy.
        //VisualElement label = new Label("Hello World! From C#");
        //root.Add(label);

        // Instantiate UXML
        VisualElement content = m_VisualTreeAsset.Instantiate();
        root.Add(content);

        content.StretchToParentSize();

        mUxmlRoot = content;

        //mTreePath = content.Q<ToolbarBreadcrumbs>("treePath");
        mGraph = content.Q("StoryGraph") as StoryGraphView;
        mPingAsset = content.Q<Button>("PingAsset");
        mSavBtn = content.Q<Button>("Save");
        mResetBtn = content.Q<Button>("Reset");
        mFileBtn = content.Q<ToolbarMenu>("File");

        RegistCallbacks();
    }

    private void OnGUI()
    {
        if (mGraph != null && Event.current.type == EventType.Layout)
        {
            mGraph.Relayout();
        }
        //if (mPlayer != null && mGraph != null)
        //{
        //    mGraph.MarkDirtyRepaint();
        //}
    }

    bool ExecuteClearGraph(bool cancelable)
    {
        if (mGraph != null && mGraph.IsDirty)
        {
            if (cancelable)
            {
                var action = EditorUtility.DisplayDialogComplex("Open TaskGraphAsset", "当前视图未保存，是否继续？", "保存", "取消", "放弃修改");
                if (action == 0)
                    mGraph.SaveGraph(false);
                else if (action == 1)
                    return false;
            }
            else
            {
                var cancel = EditorUtility.DisplayDialog("Open TaskGraphAsset", "当前视图未保存，是否继续？", "保存", "放弃修改");
                if (cancel)
                    mGraph.SaveGraph(false);
            }
        }
        return true;
    }

    void RegistCallbacks()
    {
        if (mGraph != null)
        {
            mGraph.AttachedWindow = this;
            mGraph.asset = storyGraphAsset;
            mGraph.OnIsDirty += OnGraphDirty;
            mGraph.BindRuntimeGraph(mTaskGraph);
        }
        if (mSavBtn != null)
        {
            mSavBtn.clicked += OnClickSave;
            mSavBtn.SetEnabled(mGraph != null && mGraph.IsDirty);
        }
        if (mResetBtn != null)
        {
            mResetBtn.clicked += OnClickReset;
            //mResetBtn.SetEnabled(mGraph != null && mGraph.IsDirty);
        }
        if (mPingAsset != null)
        {
            mPingAsset.clicked += OnClickPingAsset;
            mPingAsset.SetEnabled(storyGraphAsset != null);
        }

        RebuildFileMenu();
#if DEBUG_TREE
            OnSelectionChanged(true);
#endif
    }

    void UnregistCallbacks()
    {
        if (mFileBtn != null)
        {
            mFileBtn.menu.MenuItems().Clear();
        }
        if (mSavBtn != null)
        {
            mSavBtn.clicked -= OnClickSave;
        }
        if (mResetBtn != null)
        {
            mResetBtn.clicked -= OnClickReset;
        }
        if (mPingAsset != null)
        {
            mPingAsset.clicked -= OnClickPingAsset;
        }
        if (mGraph != null)
        {
            mGraph.OnIsDirty -= OnGraphDirty;
#if DEBUG_TREE
                mGraph.UnbindRuntime();
#endif
        }
    }

    void RebuildFileMenu()
    {
        if (mFileBtn != null)
        {
            mFileBtn.menu.MenuItems().Clear();
            //Func<DropdownMenuAction, DropdownMenuAction.Status> btnStat = (menu) => behaviourTreeAsset == null || mPlayer != null ? DropdownMenuAction.Status.Disabled : DropdownMenuAction.Status.Normal;
            Func<DropdownMenuAction, DropdownMenuAction.Status> btnStat2 = (menu) => storyGraphAsset == null ? DropdownMenuAction.Status.Normal : DropdownMenuAction.Status.Disabled;
            mFileBtn.menu.AppendAction("Reset", (evt) => OnClickReset(), DropdownMenuAction.Status.Normal);
            mFileBtn.menu.AppendAction("New Story", (evt) =>
            {
                if (storyGraphAsset != null && mGraph.IsDirty)
                {
                    if (!ExecuteClearGraph(true))
                        return;
                }
                storyGraphAsset = null;
            }, DropdownMenuAction.Status.Normal);
            mFileBtn.menu.AppendSeparator();
            mFileBtn.menu.AppendAction("Save", (evt) => mGraph?.SaveGraph(false), btnStat2);
            mFileBtn.menu.AppendAction("Save As", (evt) => mGraph?.SaveGraph(true), btnStat2);
        }
    }

    private void OnGraphDirty(StoryGraphView graph)
    {
        if (mGraphAsset != null)
        {
            if (graph.IsDirty)
                titleContent.text = $"{mGraphAsset.name} *";
            else
                titleContent.text = mGraphAsset.name;
        }
        if (mSavBtn != null)
        {
            mSavBtn.SetEnabled(graph.IsDirty);
        }
        //if(mResetBtn != null)
        //{
        //    mResetBtn.SetEnabled(graph.IsDirty);
        //}
    }


    private void OnClickPingAsset()
    {
        if (storyGraphAsset != null)
            EditorGUIUtility.PingObject(storyGraphAsset);
    }

    private void OnClickSave()
    {
        if (mGraph != null)
        {
            mGraph.SaveGraph(false);
            //Debug.Log("Save Data");
        }
    }

    private void OnClickReset()
    {
        if (mGraph != null /*&& m_BehaviourTreeAsset != null*/)
        {
            var path = AssetDatabase.GetAssetPath(storyGraphAsset);
            if (!string.IsNullOrEmpty(path))
                AssetDatabase.ImportAsset(path);
            mGraph.LoadGraphNodes();
            mGraph.BindRuntimeGraph(mTaskGraph);
        }
    }
}
